package com.workcell.workdata.xthings.service.impl.mqtt;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.workcell.workdata.xthings.dto.CodeChainnumVo;
import com.workcell.workdata.xthings.entity.mqtt.LevelGaugeData;
import com.workcell.workdata.xthings.mapper.mqtt.LevelGaugeDataMapper;
import com.workcell.workdata.xthings.service.factory.HardwareRealDataService;
import com.workcell.workdata.xthings.utils.DateTimeUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.ListIterator;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author zhangguangrui
 * @create 2023-05-31 8:41
 */
@Service
@DS("slave_mqtt")
@RequiredArgsConstructor
public class LevelGaugeRealDataServiceImpl extends ServiceImpl<LevelGaugeDataMapper, LevelGaugeData> implements HardwareRealDataService {

    private final RedisTemplate redisTemplate;
    private final String baseCodeBaseRedisKey = "DataQrCode_Valve_DataHourLineChartInfo_%s_%s";
    private final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");

    /**
     * 获取硬件最近的一次数据
     * @param deviceNo 设备编号
     * @param time
     * @return
     */
    @Override
    public LevelGaugeData getLatelyDataInfo(String deviceNo, String manufacturerCode, Integer time) {
        return baseMapper.getLatelyDataInfoByDeviceNo(deviceNo,manufacturerCode,time);
    }

    /**
     * 获取硬件最近六个小时的数据：折线图
     * @param deviceNo
     * @return
     */
    @Override
    public Object getDataHourLineChartInfo(String deviceNo, String manufacturerCode) {

        Map<String, LevelGaugeData> LevelGaugeDataMap = new LinkedHashMap<>(6);


        // 获取当前小时时间
        Date nowHourTime = DateTimeUtil.addHourAndFormatSM(0);
        Date nowHourTimeAddOne = DateTimeUtil.addHourAndFormatSM(1);
        checkRedisSearchDbDataChar(LevelGaugeDataMap, deviceNo, manufacturerCode, nowHourTime, nowHourTimeAddOne);
        // 处理一个小时前的数据
        Date nowHourTimeSub1 = DateTimeUtil.addHourAndFormatSM(-1);
        checkRedisSearchDbDataChar(LevelGaugeDataMap, deviceNo, manufacturerCode, nowHourTimeSub1, nowHourTime);
        // 处理两个小时前的数据
        Date nowHourTimeSub2 = DateTimeUtil.addHourAndFormatSM(-2);
        checkRedisSearchDbDataChar(LevelGaugeDataMap, deviceNo, manufacturerCode, nowHourTimeSub2, nowHourTimeSub1);
        // 处理三个小时前的数据
        Date nowHourTimeSub3 = DateTimeUtil.addHourAndFormatSM(-3);
        checkRedisSearchDbDataChar(LevelGaugeDataMap, deviceNo, manufacturerCode, nowHourTimeSub3, nowHourTimeSub2);
        // 处理四个小时前的数据
        Date nowHourTimeSub4 = DateTimeUtil.addHourAndFormatSM(-4);
        checkRedisSearchDbDataChar(LevelGaugeDataMap, deviceNo, manufacturerCode, nowHourTimeSub4, nowHourTimeSub3);
        // 处理五个小时前的数据
        Date nowHourTimeSub5 = DateTimeUtil.addHourAndFormatSM(-5);
        checkRedisSearchDbDataChar(LevelGaugeDataMap, deviceNo, manufacturerCode, nowHourTimeSub5, nowHourTimeSub4);

        // 组装数据
        JSONArray typeArray = new JSONArray();
        typeArray.add("液面高度");
        typeArray.add("液体体积");
        JSONArray timeArray = new JSONArray();
        JSONArray informationArray = new JSONArray();
        JSONObject heightObject = new JSONObject();
        JSONObject volumeObject = new JSONObject();
        heightObject.put("name","液面高度");
        volumeObject.put("name","液体体积");
        JSONArray heightArray = new JSONArray();
        JSONArray volumeArray = new JSONArray();
        // 逆序遍历
        ListIterator<Map.Entry<String, LevelGaugeData>> i = new ArrayList<>(LevelGaugeDataMap.entrySet()).listIterator(LevelGaugeDataMap.size());
        while(i.hasPrevious()) {
            Map.Entry<String, LevelGaugeData> entry = i.previous();
            timeArray.add(entry.getKey());
            heightArray.add(entry.getValue().getLiquidLevel());
            volumeArray.add(entry.getValue().getLiquidVolume());
        }
        heightObject.put("data",heightArray);
        volumeObject.put("data",volumeArray);
        informationArray.add(heightObject);
        informationArray.add(volumeObject);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("typeArray",typeArray);
        jsonObject.put("timeArray",timeArray);
        jsonObject.put("informationArray",informationArray);
        return jsonObject;
    }

    @Override
    public Page<LevelGaugeData> getHardwareDataInfo(CodeChainnumVo.SelectChainNumDataVo selectChainNumDataVo) {
        LambdaQueryWrapper<LevelGaugeData> levelGaugeDataQueryWrapper = new QueryWrapper<LevelGaugeData>().lambda()
                .eq(ObjectUtil.isNotEmpty(selectChainNumDataVo.getDeviceNo()),LevelGaugeData::getSlaveDeviceNo,selectChainNumDataVo.getDeviceNo())
                .eq(ObjectUtil.isNotEmpty(selectChainNumDataVo.getManufacturerCode()),LevelGaugeData::getManufacturerCode,selectChainNumDataVo.getManufacturerCode())
                .and(ObjectUtil.isNotEmpty(selectChainNumDataVo.getStartTime()) || ObjectUtil.isNotEmpty(selectChainNumDataVo.getEndTime()),
                i -> i.between(LevelGaugeData::getCreateTime,selectChainNumDataVo.getStartTime(),selectChainNumDataVo.getEndTime()));

        Page<LevelGaugeData> page = new Page<>(selectChainNumDataVo.getPageNum(), selectChainNumDataVo.getPageSize());
        page.addOrder(OrderItem.desc("create_date"));
        return this.page(page,levelGaugeDataQueryWrapper);
    }

    @Override
    public Object getRealData(String deviceNo) {
		LocalDateTime endTime = LocalDateTimeUtil.now();
		LocalDateTime startTime = LocalDateTimeUtil.offset(endTime, -1, ChronoUnit.MINUTES);
		LambdaQueryWrapper<LevelGaugeData> lambdaQueryWrapper = Wrappers.lambdaQuery(LevelGaugeData.class);
		lambdaQueryWrapper.eq(LevelGaugeData::getSlaveDeviceNo,deviceNo);
		lambdaQueryWrapper.between(LevelGaugeData::getCreateTime,startTime,endTime);
		lambdaQueryWrapper.orderByDesc(LevelGaugeData::getCreateTime);
		return this.getOne(lambdaQueryWrapper);
    }

    /**
     * 判断redis存在当前时间段的缓存，否则查询库存储
     * @param LevelGaugeDataMap 查询的信息存储
     * @param deviceNo 设备编号
     * @param nowHourTime 开始时间
     * @param nowHourTimeAddOne 结束时间
     */
    public void checkRedisSearchDbDataChar(Map<String, LevelGaugeData> LevelGaugeDataMap, String deviceNo, String manufacturerCode, Date nowHourTime, Date nowHourTimeAddOne){
        Object nowHourTimeDate = redisTemplate.opsForValue().get(String.format(baseCodeBaseRedisKey,deviceNo,nowHourTime));
        if (ObjectUtil.isEmpty(nowHourTimeDate)){
            nowHourTimeDate = this.baseMapper.getDataHourLineChartInfo(deviceNo, manufacturerCode, nowHourTime, nowHourTimeAddOne);
            if (ObjectUtil.isNotEmpty(nowHourTimeDate)){
                redisTemplate.opsForValue().set(String.format(baseCodeBaseRedisKey,deviceNo,nowHourTime),nowHourTimeDate,1, TimeUnit.DAYS);
            }
        }
        LevelGaugeDataMap.put(sdf.format(nowHourTime),ObjectUtil.isEmpty(nowHourTimeDate)?new LevelGaugeData():(LevelGaugeData) nowHourTimeDate);
    }

}
